package com.gragra.sampling.nonproj.structures.tests;
import static org.junit.Assert.*;
import java.util.ArrayList;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.junit.Before;
import org.junit.Test;
import com.gragra.sampling.ThreadedUniformAccess;
import com.gragra.sampling.binary.ConvertSample;
import com.gragra.sampling.nonproj.ConvertHeadedFactory;
import com.gragra.sampling.nonproj.ConvertHeadedStructure;
import com.gragra.sampling.nonproj.FixedParsesAssigner;
import com.gragra.sampling.nonproj.Uniform;
import com.gragra.sampling.nonproj.generators.CreateDependencyCorpus;
import com.gragra.sampling.nonproj.generators.projective.CreateMHProjectiveCorpus;
import com.gragra.sampling.nonproj.structures.nonprojective.NonProjDepdTree;
import com.gragra.util.StringToInt;
/**
 * 
 * @author Christoph Teichmann
 * 10.10.2013
 */
public class TestMHProjectiveDepdTree
{
	/**
	 * 
	 */
	private ThreadedUniformAccess tua;
	/**
	 * 
	 */
	private NonProjDepdTree tree;
	@Before
	public void setUp() throws Exception
	{
		CreateDependencyCorpus cre = new CreateMHProjectiveCorpus(new ConvertHeadedFactory());
		tree = cre.makeTree("0|0 1|1 2|2 3|3", 3, 0.1);
		tua = new ThreadedUniformAccess(3);
	}
	@Test
	public void testGetNumberOfThreads()
	{assertEquals(3,tree.getNumberOfThreads());}
	@Test
	public void testIsChild()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 1, 0);
		assertTrue(tree.isChild(0, tree.getRootPosition(), 0));
		for(int i=0;i<tree.getLength();++i)
		{assertFalse(tree.isChild(0, i, 0));}
		assertTrue(tree.isChild(1, 0, 0));
		for(int i=1;i<tree.getLength()+1;++i)
		{assertFalse(tree.isChild(1, i, 0));}
	}
	@Test
	public void testNumberOfChildren()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		assertEquals(tree.numberOfChildren(0, 0),2);
		assertEquals(tree.numberOfChildren(1, 0),0);
		assertEquals(tree.numberOfChildren(2, 0),0);
		assertEquals(tree.numberOfChildren(3, 0),1);
		assertEquals(tree.numberOfChildren(tree.getRootPosition(), 0),1);
	}
	@Test
	public void testGetParentPosition()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		assertEquals(tree.getParentPosition(0,0), tree.getRootPosition());
		assertEquals(tree.getParentPosition(1,0), 0);
		assertEquals(tree.getParentPosition(2,0), 3);
		assertEquals(tree.getParentPosition(3,0), 0);
	}
	@Test
	public void testGetParentTag()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		assertEquals(tree.getParentTag(0, 0),-1);
		assertEquals(tree.getParentTag(1, 0),StringToInt.ensure("0"));
		assertEquals(tree.getParentTag(2, 0),StringToInt.ensure("3"));
		assertEquals(tree.getParentTag(3, 0),StringToInt.ensure("0"));
	}
	@Test
	public void testGetParentWord()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		assertEquals(tree.getParentWord(0, 0),-1);
		assertEquals(tree.getParentWord(1, 0),StringToInt.ensure("0"));
		assertEquals(tree.getParentWord(2, 0),StringToInt.ensure("3"));
		assertEquals(tree.getParentWord(3, 0),StringToInt.ensure("0"));
	}
	@Test
	public void testGetConverter()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		tree.setBest(0);
		ConvertSample cs = tree.getConverter();
		assertEquals(cs.getBest(tree, null),"4 0 3 0");
	}
	@Test
	public void testGetBest()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		tree.setBest(0);
		assertEquals(tree.getBest(null),"4 0 3 0");
	}
	@Test
	public void testGetRootPosition()
	{assertEquals(tree.getRootPosition(),tree.getLength());}
	@Test
	public void testGetHeadPosition()
	{
		tree.initialize(null, tua);
		tree.setNewHead(0, tree.getRootPosition(), 0);
		tree.setNewHead(1, 0, 0);
		tree.setNewHead(2, 3, 0);
		tree.setNewHead(3, 0, 0);
		assertEquals(tree.getHeadPosition(0,0), tree.getRootPosition());
		assertEquals(tree.getHeadPosition(1,0), 0);
		assertEquals(tree.getHeadPosition(2,0), 3);
		assertEquals(tree.getHeadPosition(3,0), 0);
	}
	@Test
	public void testGetDependencyRootPosition()
	{assertEquals(tree.getDependencyRootPosition(),tree.getLength());}
	@Test
	public void testResample1()
	{
		CreateDependencyCorpus cre = new CreateMHProjectiveCorpus(new ConvertHeadedFactory());
		tree = cre.makeTree("0|0 1|1 2|2 3|3 4|4", 3, 0.1);
		tua = new ThreadedUniformAccess(3);
		Uniform uni = new Uniform(3);
		tree.initialize(uni, tua);
		for(int i=0;i<10000;++i)
		{
			for(int thread=0;thread<3;++thread)
			{tree.resample(uni, 1.0, thread, tua);}
			tree.addSample();
			for(int thread=0;thread<3;++thread)
			{assertTrue(isProjective(thread));}
		}
		Object2IntOpenHashMap<String> m = (((ConvertHeadedStructure) tree.getConverter()).getCounts());
		assertEquals(m.size(),273);
		double max = 0.0;
		for(String s : m.keySet())
		{
			double v1 = m.getInt(s);
			for(String t : m.keySet())
			{
				double v2 = m.getInt(t);
				max = Math.max(max, v1/v2);
			}
		}
		assertEquals(max,1.0,1.0);
	}
	@Test
	public void testResample2()
	{
		CreateDependencyCorpus cre = new CreateMHProjectiveCorpus(new ConvertHeadedFactory());
		tree = cre.makeTree("0|0 1|1 2|2 3|3 4|4", 5, 0.1);
		tua = new ThreadedUniformAccess(5);
		ArrayList<String> golds = new ArrayList<String>();
		golds.add("1 3 3 5 3");
		golds.add("2 2 5 2 2");
		FixedParsesAssigner fpa = new FixedParsesAssigner(5, 3.0, 2, golds);
		tree.initialize(fpa, tua);
		for(int i=0;i<10000;++i)
		{
			for(int thread=0;thread<5;++thread)
			{tree.resample(fpa, 1.0, thread, tua);}
			tree.addSample();
			for(int thread=0;thread<3;++thread)
			{assertTrue(isProjective(thread));}
		}
		assertTrue(tree.getNumberSeen(golds.get(0))>0);
		double max = Math.max((double) tree.getNumberSeen(golds.get(0))/(double) tree.getNumberSeen(golds.get(1)), (double) tree.getNumberSeen(golds.get(1))/(double) tree.getNumberSeen(golds.get(0)));
		assertEquals(max,1.0,1.0);
	}
	/**
	 * 
	 * @param thread
	 * @return
	 */
	private boolean isProjective(int thread)
	{
		for(int i=0;i<tree.getLength();++i)
		{
			int head = tree.getHeadPosition(i, thread);
			int from = Math.min(i, head);
			int to = Math.max(head, i);
			for(int j=0;j<tree.getLength();++j)
			{
				head = tree.getHeadPosition(j, thread);
				if(j < from && head > from && to > head)
				{return false;}
				if(j>from&&((j<to && (head < from || head > to)) || (j>to && head < to && head > from)))
				{return false;}
			}
		}
		return true;
	}
}